/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package util.ejb;

import entities.tools.FilledForm;
import entities.tools.Form;
import entities.tools.Question;
import entities.users.CompanyOwner;
import entities.users.FormOwner;
import entities.users.FormSigner;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * Form used for performing operations on the form entities TODO: Add
 * transaction mechanism to make the bean optymalized TODO: Add metods
 * performing mass operations: for example adding few questions same time
 *
 * @author Marek
 */
@Stateless

public class FormBean implements FormBeanInterface {

    @PersistenceContext(name = "test", unitName = "JEE-study-warPU")
    private EntityManager em;


    /**
     * Create the new form entity
     *
     * @return the created before, form instance
     */

    //This method here work correctly 
    @Override
    public Form createNewForm() {
        Form form = new Form();
        em.persist(form);
        return form;
    }

    /**
     * Method Deletes the existing form entity
     *
     * @param form
     * @throws java.lang.Exception
     */
    //TODO: check, if together with the form, are also deleted connected with the form, questions. They should be deleted, when the form is deleted
    //TODO: It seams that this method is working corretly 
    @Override
    public void deleteForm(Form detachedForm) {
        Form menagedForm = em.find(Form.class,detachedForm.getId());
        if(null!=menagedForm){
          Long size = (Long)em.createQuery("select count(filledForm) from Form form,FilledForm filledForm where form=:form and form=filledForm.form").setParameter("form",menagedForm).getSingleResult();
          if(size>0){
              System.out.println("Cannot be deleted becouse somone ansfered it before "+detachedForm.getId());  
              return;
          } else {
             em.remove(menagedForm);
             detachedForm = null;
          }
       } else {
           System.out.println("ERROR ERROR ERROR for "+detachedForm.getId());
       }
      
                    //TODO: create a class for each type of custom exceptions throwed by methods
                //throw new Exception("Form can not be deleted, becouse it has been filled by FormSigner before");
           
                //TODO: create a class for each type of custom exceptions throwed by methods
            //throw new Exception("Form don't exist, so it can not be deleted.");
      
    }

    /**
     * Method updates the existing form.
     *
     * @param form
     * @throws java.lang.Exception
     */
    //This method works corretly
    @Override
    public void updateForm(Form form){
       if(null!=em.find(Form.class,form.getId())){
          em.merge(form);   
       } else {
           System.out.println("ERROR ERROR ERROR for "+form.getId());
       }
    }

    /**
     * Methods return the list of all existing forms TODO: add argument, which
     * will specify sort by argument
     *
     * @return list of all existing in db forms
     */
    //This method works correctly
    @Override
    public List<Form> getAllForms()  {
        Query query = em.createQuery("SELECT form FROM Form form", Form.class);
        List<Form> forms = query.getResultList();
        return forms;
    }

    /**
     * Methods return the list of all existing forms, belonging to specified
     * CompanyOwner TODO: add argument, which will specify sort by argument
     *
     * @param companyOwner
     * @return list of all existing in db forms
     * @throws java.lang.Exception
     */
    @Override
    public List<Form> getAllForms(CompanyOwner companyOwner) throws Exception {
        CompanyOwner tmp_companyOwner = em.find(CompanyOwner.class, companyOwner.getId());

        if (null != tmp_companyOwner) {
            return tmp_companyOwner.getForms();
        } else {
            throw new Exception("CompanyOwner specyfied by you, doesn't exist");
        }
    }

    /**
     * Methods return the list of all existing forms, belonging to specified
     * FormOwner TODO: add argument, which will specify sort by argument
     *
     * @param formOwner
     * @return list of all existing in db forms
     * @throws java.lang.Exception
     */
    @Override
    public List<Form> getAllForms(FormOwner formOwner) throws Exception {
        FormOwner tmp_formOwner = em.find(FormOwner.class, formOwner.getId());
        if (null != tmp_formOwner) {
            return tmp_formOwner.getForms();
        } else {
            throw new Exception("FormOwner specyfied by you, doesn't exist");
        }
    }

    /**
     * Get the existing form, assigned to the id number
     *
     * @param id
     * @return form assigned to the id number
     * @throws java.lang.Exception
     */
    //This method works corretly
    @Override
    public Form getExistingForm(Long id){
        Form tmp_form = em.find(Form.class, id);
        if (null != tmp_form) {
            return tmp_form;
        } else {
            System.out.println("Form with the id=" + id + ", doesn't exist");
            return null;
        }
    }

    /**
     * Adds the new question to the existing form
     *
     * @param detachedForm
     * @param question
     * @throws java.lang.Exception
     */
    //This method works fine
    @Override
    public Question createNewQuestion(Form detachedForm){
        //TODO: mayby it's better to change find variable to refresh, and catch exception here :-)
        Form attachedForm = em.find(Form.class, detachedForm.getId());
        if (null == attachedForm) {
            //throw new Exception("The form, specified by you, doesn't exist in the database");
            System.out.println("ERROR ERROR ERROR: "+detachedForm.getId());
            return null;
        }
        if (!attachedForm.getFilledForms().isEmpty()) {
            //throw new Exception("Adding new question to form, that had been filled before, is permited");
        }
        Question question = new Question();
        question.setForm(detachedForm);
        detachedForm.getQuestions().add(question);
        em.persist(question);
        em.merge(detachedForm);
        return question;
    }

    /**
     * Method is removing the relation, and also is removing the question
     * entity. TODO: Check: If I removed relation between form and question, the
     * question entity ware be also deleted from database? TODO: Secure the
     * possible scenario of deleting the question which is connected with filled
     * before answers
     *
     * @param form
     * @param detachedQuestion
     * @return 
     * @throws java.lang.Exception
     */
    //This method works fine
    @Override
    public boolean removeQuestion(Form form, Question detachedQuestion) {
        Form tmp_form = em.find(Form.class, form.getId());
        Question attachedQuestion = em.find(Question.class,detachedQuestion.getId());
        if (null == tmp_form) {
            System.out.println("removeQuestion():The form, specified by you, doesn't exist in the database");
            return false;
        }
        if (attachedQuestion.getForm()!=tmp_form) {
            System.out.println("removeQuestion():This question is not a part of this form. It cannot be removed");
            return false;
        }
        if (!attachedQuestion.getAnswers().isEmpty()) {
            System.out.println("removeQuestion():Question cannot be removed, becouse someone had answered it before");
            return false;
        }
        tmp_form.getQuestions().remove(attachedQuestion);
        em.merge(tmp_form);
        em.remove(attachedQuestion);
        form.setQuestions(tmp_form.getQuestions());
        return true;
    }

    //
    /**
     * Method is performing update of the question connected with the existing
     * form. Question must have not any Answers linked to it.
     *
     * @param form
     * @param detachedQuestion
     * @throws java.lang.Exception
     */
    //This method works fine
    @Override
    public boolean updateQuestion(Form form, Question detachedQuestion){
        Form tmp_form = em.find(Form.class, form.getId());
        if (null == tmp_form) {
            System.out.println("The form, specified by you, doesn't exist in the database");
            return false ;
        }
        Question attachedQuestion = em.find(Question.class,detachedQuestion.getId());
        if (null == attachedQuestion) {
            System.out.println("The question, specified by you, doesn't exist in the database");
            return false ;
        }
        if (attachedQuestion.getForm() != tmp_form) {
            System.out.println("This question is not a part of this form. It cannot be updated");
            return false;
        }
        if (!attachedQuestion.getAnswers().isEmpty()) {
            System.out.println("Question cannot be updated becouse, someone had answered it before");
            return false;
        }
        detachedQuestion.setForm(tmp_form);
        em.merge(detachedQuestion);
        em.merge(tmp_form);
        return true;
    }

    /**
     * Searches the database for an entity of the question, containing
     * question_id, and also check if this question is part of specified form
     * Performs the check if the specified form exists in database.
     *
     * @param dattachedForm
     * @param questionId
     * @return search result
     * @throws java.lang.Exception
     */
    //TODO: This method works fine
    @Override
    public Question getQuestion(Form dattachedForm, Long questionId){
        Form attachedForm = em.find(Form.class, dattachedForm.getId());
        Question attachedQuestion = em.find(Question.class,questionId);
        if (null == attachedForm) {
            System.out.println("Form.qetQuestion():The form, specified by you, doesn't exist in the database");
            return null;
        }
        if (null == attachedQuestion) {
            System.out.println("Form.qetQuestion():Question with the id=" + questionId + " doesn't exist in database");
            return null;
        }
        if (attachedQuestion.getForm()!=attachedForm) {
            System.out.println("Form.qetQuestion():The question with the id=" + questionId + " is not a part of specified form");
            return null;
        }
        return attachedQuestion;
    }

    /**
     * Get all questions which belongs to the existing form. Also performs the
     * check if the specified form exist in the database.
     *
     * @param detachedForm
     * @return
     * @throws java.lang.Exception
     */
    //This method works fine
    @Override
    public List<Question> getAllQuestions(Form detachedForm){ 
        Form tmp_form = em.find(Form.class, detachedForm.getId());
        if (null != tmp_form) {
            //TODO: This code need to be optymized. Now it is running slow.
            //It is important, to make the copy of the question collection, becouse we don't want to allow the user, permissions to delete, update, add question, by modyfications of this question collection. All operations on entities should be menagaed by formBean
            Object[] questions = tmp_form.getQuestions().toArray();
            ArrayList<Question> questions_list = new ArrayList<Question>();
            for(Object question:questions){
                questions_list.add((Question)question);
            }
            return questions_list;
        } else {
            System.out.println("The form, specified by you, doesn't exist in the database");
            return null;
        }
    }

    /**
     * Method returns all FilledForm instances connected with the existing Form
     * Also performs the check, if the specified form, exist in the database.
     *
     * @param form
     * @return returns all FilledForm instances connected with the existing F
     * @throws java.lang.Exceptionorm
     */
    @Override
    public List<FilledForm> getFilledForms(Form form) throws Exception {

        Form tmp_form = em.find(Form.class, form.getId());

        if (null != tmp_form) {
            return tmp_form.getFilledForms();
        } else {
            throw new Exception("The form, specified by you, doesn't exist in the database");
        }
    }

    /**
     * Method gets the existing FilledForm instance, linked with the existing
     * form Performs the check, if the specified Form exist in database.
     * Performs the check, if the FilledForm with id is in relation with the
     * specified form.
     *
     * @param form
     * @param filledFormId
     * @return the existing FilledForm instance
     * @throws java.lang.Exception
     */
    @Override
    public FilledForm getFilledForm(Form form, Long filledFormId) throws Exception {

        Form tmp_form = em.find(Form.class, form.getId());

        if (null == tmp_form) {
            throw new Exception("The form, specified by you, doesn't exist in the database");
        }

        FilledForm filledForm = em.find(FilledForm.class, filledFormId);

        if (null == filledForm) {
            throw new Exception("FilledForm with id=" + filledFormId + " doesn't exist in the database.");
        }

        int index = tmp_form.getFilledForms().indexOf(filledForm);

        if (-1 == index) {
            throw new Exception("Specyfied form doesn't contain FilledForm with id=" + filledFormId);
        }
        return filledForm;
    }
    /**
     * (Dangerous) Method is bypasses security policy. Normally form cannot be deleted, when it had been filled by someone before.
     * Method is performing delete operation on all instances of FilledForm entity, related to the Form, specified by param, and than it deletes also that Form entity, specified by param.
     * @param detachedForm
     * @return true - if operation succeeded false - otherwise
     */
    @Override
    public boolean forcedDeleteForm(Form detachedForm){
        Form attachedForm = em.find(Form.class, detachedForm.getId());
        if (null == attachedForm) {
            System.out.println("FormBean:forcedDeleteForm():The form, specified by you, doesn't exist in the database");
            return false;
        }
        List<FilledForm> filledForms = em.createQuery("select filledForm from Form form,FilledForm filledForm where form=filledForm.form and form.id=:id",FilledForm.class).setParameter("id",attachedForm.getId()).getResultList();
        for(FilledForm filledForm:filledForms){
            em.remove(filledForm);
        }
        em.remove(attachedForm);
        return true;
    }
}
